﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.CompilerServices;

namespace RDPRemoteObject
{
    public class UserLogin : MarshalByRefObject, RDPCommon.IUserLogin 
    {
        public static object privateObjectLock = new object();

        //客户端注册的响应服务端对其在线测试的事件集合
        static Dictionary<string, RDPCommon.OnlienTestEventHandler>
        m_LoginTest = new Dictionary<string, RDPCommon.OnlienTestEventHandler>();

        //主要,以用户 SessionId 为 Key 保存在线用户集合
        static Dictionary<string, RDPCommon.Client.ClinetInfo>
        m_Users_SessionId = new Dictionary<string,RDPCommon.Client.ClinetInfo>();

        //以DB_UserCode 为Key 保存在线用户信息
        static Dictionary<string, RDPCommon.Client.ClinetInfo>
        m_Users_DB_UserCode = new Dictionary<string, RDPCommon.Client.ClinetInfo>();

        //客户端注册的用户登录事件集合,主要用于客户端刷新在线用户列表
        static Dictionary<string, RDPCommon.LoginNotifyEventHandler>
        m_LoginNotify = new Dictionary<string, RDPCommon.LoginNotifyEventHandler>();

        //客户端注册的用户注销事件集合,主要用于客户端刷新在线用户列表
        static Dictionary<string, RDPCommon.LogoutNotifyEventHandler>
        m_LogoutNotify = new Dictionary<string, RDPCommon.LogoutNotifyEventHandler>();

        public static event RDPCommon.UserLoginEventHandler UserLoginEvent;//在服务端触发用户登录事件，以采取相应处理
        public static event RDPCommon.UserLogoutEventHandler UserLogoutEvent; //在服务端触发用户注销事件，以采取相应处理

        /// <summary>
        /// 是否启动服务
        /// </summary>
        public static bool Servicing = false;
        
        /// <summary>
        /// 由客户端用于用户登录
        /// </summary>
        /// <param name="clientInfo"></param>
        /// <returns></returns>
        public object[] Login(RDPCommon.Client.ClinetInfo clientInfo)
        {
            lock (privateObjectLock)
            {
                object[] rtn = new object[] { 0, null };
                if (Servicing)
                {
                    //在同一个DB同名用户如已登录,则要看其是否在线,如在线则不允许此用户登录
                    //否则清除已离线用户,让此用户登录
                    string _DBUser = clientInfo.DB + "_" + clientInfo.UserCode;
                    if (m_Users_DB_UserCode.ContainsKey(clientInfo.DB + "_" + clientInfo.UserCode))
                    {
                        RDPCommon.Client.ClinetInfo ExistCI = m_Users_DB_UserCode[_DBUser];
                        object[] ortn = OnLineTest(ExistCI);
                        if (ortn != null && Convert.ToInt32(ortn[0]) != 0)
                        {
                            //经测试已离线,则要清除此用户信息,并让此用户登录
                            ClearClientRegInfo(ExistCI);

                            m_Users_DB_UserCode.Add(_DBUser, clientInfo);
                        }
                        else
                        {
                            //原用户仍在线,则不允许重复登录
                            //rtn[0] = 1;
                            //rtn[1] = new Exception("该用户代码已登录,本系统不允许重复登录.");
                            //return rtn;
                        }
                    }
                    else
                    {
                        m_Users_DB_UserCode.Add(_DBUser, clientInfo);
                    }

                    if (!m_Users_SessionId.ContainsKey(clientInfo.SessionID))
                        m_Users_SessionId.Add(clientInfo.SessionID, clientInfo);
                    if (UserLoginEvent != null)
                        UserLoginEvent(clientInfo);
                    rtn = LoginNotify(clientInfo);//通知所有客户端
                }
                else
                {
                    rtn[0] = 1;
                    rtn[1] = new Exception("服务端暂停服务,请稍候再试.");
                }
                return rtn;
            }
        }

        /// <summary>
        /// 由客户端用于用户登录
        /// </summary>
        /// <param name="clientInfo"></param>
        /// <returns></returns>
        public object[] Logout(RDPCommon.Client.ClinetInfo clientInfo)
        {
            lock (privateObjectLock)
            {
                object[] rtn = new object[] { 0, null };
                if (Servicing)
                {
                    ClearClientRegInfo(clientInfo);

                    if (UserLogoutEvent != null)
                        UserLogoutEvent(clientInfo);
                    rtn = LogoutNotify(clientInfo); //通知所有客户端
                }
                else
                {
                    rtn[0] = 1;
                    rtn[1] = new Exception("服务端暂停服务,请稍候再试.");
                }
                return rtn;
            }
        }

        /// <summary>
        /// 类似广播,测试指定用户是否在线
        /// </summary>
        /// <param name="clientInfo"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public object[] OnLineTest(RDPCommon.Client.ClinetInfo clientInfo)
        {
            lock (privateObjectLock)
            {
                object[] rtn = new object[] { 0, null };
                if (m_LoginTest.ContainsKey(clientInfo.SessionID))
                {
                    try
                    {
                        m_LoginTest[clientInfo.SessionID](clientInfo);
                    }
                    catch (Exception ex)
                    {
                        rtn[0] = 1;
                        rtn[1] = new Exception("客户端已离线.");
                        //统一记入日志
                        RDPCommon.Util.SaveLog(RDPCommon.Util.GetExceptionMsg(ex));
                    }
                }
                return rtn;
            }
        }

        /// <summary>
        /// 当用户离线后，注销相应已注册的事件
        /// </summary>
        /// <param name="clientInfo"></param>
        public static void ClearClientRegInfo(RDPCommon.Client.ClinetInfo clientInfo)
        {
            if (m_LoginNotify.ContainsKey(clientInfo.SessionID))
                m_LoginNotify.Remove(clientInfo.SessionID);

            if (m_LogoutNotify.ContainsKey(clientInfo.SessionID))
                m_LogoutNotify.Remove(clientInfo.SessionID);

            if (m_LoginTest.ContainsKey(clientInfo.SessionID))
                m_LoginTest.Remove(clientInfo.SessionID);

            if (m_Users_SessionId.ContainsKey(clientInfo.SessionID))
                m_Users_SessionId.Remove(clientInfo.SessionID);

            if (m_Users_DB_UserCode.ContainsKey(clientInfo.DB + "_" + clientInfo.UserCode))
                m_Users_DB_UserCode.Remove(clientInfo.DB + "_" + clientInfo.UserCode);
        }

        /// <summary>
        /// 类似广播
        /// </summary>
        /// <param name="clientInfo"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public object[] LoginNotify(RDPCommon.Client.ClinetInfo clientInfo)
        {
            lock (privateObjectLock)
            {
                object[] rtn = new object[] { 0, null };
                foreach (KeyValuePair<string, RDPCommon.LoginNotifyEventHandler> pk in m_LoginNotify)
                {
                    try
                    {
                        pk.Value(clientInfo);
                    }
                    catch (Exception ex)
                    {
                        //rtn[0] = 1;
                        //rtn[1] = new Exception("客户端已离线.");
                        //统一记入日志
                        RDPCommon.Util.SaveLog(RDPCommon.Util.GetExceptionMsg(ex));
                        if (m_LoginNotify.ContainsKey(clientInfo.SessionID))
                            m_LoginNotify.Remove(clientInfo.SessionID);
                    }
                }
                return rtn;
            }
        }

        /// <summary>
        /// 类似广播
        /// </summary>
        /// <param name="clientInfo"></param>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.Synchronized)]
        public object[] LogoutNotify(RDPCommon.Client.ClinetInfo clientInfo)
        {
            lock (privateObjectLock)
            {
                object[] rtn = new object[] { 0, null };
                foreach (KeyValuePair<string, RDPCommon.LogoutNotifyEventHandler> pk in m_LogoutNotify)
                {
                    try
                    {
                        pk.Value(clientInfo);
                    }
                    catch (Exception ex)
                    {
                        //rtn[0] = 1;
                        //rtn[1] = new Exception("客户端已离线.");
                        //统一记入日志
                        RDPCommon.Util.SaveLog(RDPCommon.Util.GetExceptionMsg(ex));
                        if (m_LogoutNotify.ContainsKey(clientInfo.SessionID))
                            m_LogoutNotify.Remove(clientInfo.SessionID);
                    }
                }
                return rtn;
            }
        }

        public void AddEventReappear(string clientId, RDPCommon.OnlienTestEventHandler re)
        {
            lock (privateObjectLock)
            {
                if (!m_LoginTest.ContainsKey(clientId))
                    m_LoginTest.Add(clientId, re);
            }
        }

        public void RemoveEventReappear(string clientId, RDPCommon.OnlienTestEventHandler re)
        {
            lock (privateObjectLock)
            {
                if (m_LoginTest.ContainsKey(clientId))
                    m_LoginTest.Remove(clientId);
            }
        }

        public void AddLoginNotifyEvent(string clientId, RDPCommon.LoginNotifyEventHandler re)
        {
            lock (privateObjectLock)
            {
                if (!m_LoginNotify.ContainsKey(clientId))
                    m_LoginNotify.Add(clientId, re);
            }
        }

        public void RemoveLoginNotifyEvent(string clientId, RDPCommon.LoginNotifyEventHandler re)
        {
            lock (privateObjectLock)
            {
                if (m_LoginNotify.ContainsKey(clientId))
                    m_LoginNotify.Remove(clientId);
            }
        }

        public void AddLogoutNotifyEvent(string clientId, RDPCommon.LogoutNotifyEventHandler re)
        {
            lock (privateObjectLock)
            {
                if (!m_LogoutNotify.ContainsKey(clientId))
                    m_LogoutNotify.Add(clientId, re);
            }
        }

        public void RemoveLogoutNotifyEvent(string clientId, RDPCommon.LogoutNotifyEventHandler re)
        {
            lock (privateObjectLock)
            {
                if (m_LogoutNotify.ContainsKey(clientId))
                    m_LogoutNotify.Remove(clientId);
            }
        }

        /// <summary>
        /// 返回在线用户列表
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, RDPCommon.Client.ClinetInfo> GetActiveUsers()
        {
            lock (privateObjectLock)
            {
                return m_Users_SessionId;
            }
        }

        /// <summary>
        /// 将对象的租用周期改变为无限
        /// </summary>
        /// <returns></returns>
        public override object InitializeLifetimeService()
        {
            return null;
        }
    }
}
